package com.restphp.java.utils.http.client;

import com.alibaba.fastjson.JSONObject;
import com.restphp.java.utils.http.consts.HttpMethod;

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by sofical on 2020/7/13.
 */
public class RestClientUtils {
    private HttpClientLogger logger = null;
    public RestClientUtils() {
    }
    public RestClientUtils(HttpClientLogger logger) {
        this.logger = logger;
    }
    /**
     * get 请求.
     * @param uri 接口地址，以"/"开头
     * @return api response as String.
     */
    public String get (String uri) {
        return this.request(HttpMethod.GET, uri, null, null, null, String.class);
    }

    /**
     * get 请求.
     * @param uri 接口地址，以"/"开头.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T get (String uri, Class<T> tClass) {
        return this.request(HttpMethod.GET, uri, null, null, null, tClass);
    }

    /**
     * get 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T get (String uri, Map<String, String> queryParams, Class<T> tClass) {
        return this.request(HttpMethod.GET, uri, queryParams, null, null, tClass);
    }

    /**
     * get 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param header 自定义头信息.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T get (String uri, Map<String, String> queryParams,
                      HashMap<String, String> header, Class<T> tClass) {
        return this.request(HttpMethod.GET, uri, queryParams, header, null, tClass);
    }

    /**
     * POST 请求.
     * @param uri 接口地址，以"/"开头.
     * @param bodyData body参数.
     * @return api response.
     */
    public String post (String uri, Object bodyData) {
        return this.request(HttpMethod.POST, uri, null, null, bodyData, String.class);
    }

    /**
     * POST 请求.
     * @param uri 接口地址，以"/"开头.
     * @param bodyData body参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T post (String uri, Object bodyData, Class<T> tClass) {
        return this.request(HttpMethod.POST, uri, null, null, bodyData, tClass);
    }

    /**
     * POST 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param bodyData body参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T post (String uri, Map<String, String> queryParams, Object bodyData, Class<T> tClass) {
        return this.request(HttpMethod.POST, uri, queryParams, null, bodyData, tClass);
    }

    /**
     * POST 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param header 头部信息.
     * @param bodyDta body参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T post (String uri, Map<String, String> queryParams, Map<String, String> header,
                       Object bodyDta, Class<T> tClass) {
        return this.request(HttpMethod.POST, uri, queryParams, header, bodyDta, tClass);
    }

    /**
     * PUT 请求.
     * @param uri 接口地址，以"/"开头.
     * @param bodyData body参数.
     * @return api response.
     */
    public String put (String uri, Object bodyData) {
        return this.request(HttpMethod.PUT, uri, null, null, bodyData, String.class);
    }

    /**
     * PUT 请求.
     * @param uri 接口地址，以"/"开头.
     * @param bodyData body参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T put (String uri, Object bodyData, Class<T> tClass) {
        return this.request(HttpMethod.PUT, uri, null, null, bodyData, tClass);
    }

    /**
     * PUT 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param bodyData body参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T put (String uri, Map<String, String> queryParams, Object bodyData, Class<T> tClass) {
        return this.request(HttpMethod.PUT, uri, queryParams, null, bodyData, tClass);
    }

    /**
     * PUT 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param header 头部信息.
     * @param bodyDta body参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T put (String uri, Map<String, String> queryParams, HashMap<String, String> header,
                      Object bodyDta, Class<T> tClass) {
        return this.request(HttpMethod.PUT, uri, queryParams, header, bodyDta, tClass);
    }

    /**
     * delete 请求.
     * @param uri 接口地址，以"/"开头.
     * @return api response.
     */
    public String delete (String uri) {
        return this.request(HttpMethod.DELETE, uri, null, null, null, String.class);
    }

    /**
     * delete 请求.
     * @param uri 接口地址，以"/"开头.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T delete (String uri, Class<T> tClass) {
        return this.request(HttpMethod.DELETE, uri, null, null, null, tClass);
    }

    /**
     * delete 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T delete (String uri, Map<String, String> queryParams, Class<T> tClass) {
        return this.request(HttpMethod.DELETE, uri, queryParams, null, null, tClass);
    }

    /**
     * delete 请求.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param header 自定义头信息.
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T delete (String uri, Map<String, String> queryParams,
                         Map<String, String> header, Class<T> tClass) {
        return this.request(HttpMethod.DELETE, uri, queryParams, header, null, tClass);
    }

    /**
     * 响应结果.
     */
    private ClientResponse clientResponse;

    /**
     * 获取返回Http状态.
     * @return status.
     */
    public Integer getReponseStatus() {
        return clientResponse.getStatus();
    }

    /**
     * 获取响应内容.
     * @param tClass 转换目标类.
     * @param <T> T.
     * @return 响应内容.
     */
    public <T> T getClientResponse(Class<T> tClass) {
        if ("java.lang.String".equals(tClass.getName())) {
            return (T) clientResponse.getBody();
        }
        return JSONObject.parseObject(clientResponse.getBody(), tClass);
    }

    /**
     * 通用接口请求.
     * @param method http method.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param header 自定义头信息.
     * @param bodyData 请求body数据
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T request(HttpMethod method, String uri, Map<String, String> queryParams,
                         Map<String, String> header, Object bodyData, Class<T> tClass) {
        String content = null == bodyData ? null : JSONObject.toJSONString(bodyData);
        return this.requestStringData(method, uri, queryParams, header, content, tClass);
    }

    /**
     * 通用接口请求.
     * @param method http method.
     * @param uri 接口地址，以"/"开头.
     * @param queryParams query参数.
     * @param header 自定义头信息.
     * @param bodyData 请求body数据
     * @param tClass 返回数据类型.
     * @param <T> T.
     * @return api response.
     */
    public <T> T requestStringData(HttpMethod method, String uri, Map<String, String> queryParams,
                         Map<String, String> header, String bodyData, Class<T> tClass) {

        //请求地址
        String url = uri;
        if (null != queryParams) {
            String queryString = "";
            for (Map.Entry<String, String> param : queryParams.entrySet()) {
                try {
                    queryString += ("".equals(queryString) ? "" : "&") + param.getKey() + "=" + URLEncoder.encode(param.getValue(), "UTF-8");
                } catch (Exception e) {

                }
            }
            if (!"".equals(queryString)) {
                url += "?" + queryString;
            }
        }

        //请求内容
        String content = null == bodyData ? null : bodyData;
        if (null == header) {
            header = new HashMap<>();
            header.put("Content-Type", "application/json;charset=utf8");
        }
        //请求结果
        this.clientResponse = HttpClientUtils.request(url, content, method.name(), header);
        //记录日志.
        if (null != logger) {
            this.logger.write(method, url, header, bodyData, this.clientResponse);
        }
        if (199 < this.clientResponse.getStatus() && this.clientResponse.getStatus() < 299) {
            return this.getClientResponse(tClass);
        } else {
            return null;
        }
    }
}
